#include "comm/my_spinlock.h"

#include <pthread.h>

void test_spinlock() {
    my_spinlock_t lock;
    my_spinlock_init(&lock);

    my_spinlock_lock(&lock);
    my_spinlock_unlock(&lock);

    my_spinlock_lock(&lock);
    assert(!my_spinlock_trylock(&lock));
    my_spinlock_unlock(&lock);

    assert(my_spinlock_trylock(&lock));
    my_spinlock_unlock(&lock);
}

#define N 10
#define M 1000000
my_spinlock_t g_lock;
int g_i = 0;

void *do_test(void *arg) {
    (void)arg;

    for (int i = 0; i < M; i++) {
        my_spinlock_lock(&g_lock);
        g_i++;
        my_spinlock_unlock(&g_lock);
    }

    return NULL;
}

void test_mult_thread_lock() {
    my_spinlock_init(&g_lock);
    pthread_t tids[N];

    for (int i = 0; i < N; i++) {
        pthread_t tid;
        pthread_create(&tid, NULL, do_test, NULL);
        tids[i] = tid;
    }

    for (int i = 0; i < N; i++) {
        pthread_join(tids[i], NULL);
    }

    assert(g_i == N * M);
}

void *do_wait_group_done(void *arg)
{
    my_spin_wait_group_t *wait_group = arg;
    my_spin_wait_group_done(wait_group);
    sleep(5);
    my_spin_wait_group_done(wait_group);
    return NULL;
}

void test_spin_wait_group()
{
    pthread_t tid;
    my_spin_wait_group_t wait_group;
    my_spin_wait_group_init(&wait_group);

    my_spin_wait_group_add(&wait_group, 2);
    pthread_create(&tid, NULL, do_wait_group_done, &wait_group);
    my_spin_wait_group_wait(&wait_group);

    DD("wait_group wait done");

    pthread_join(tid, NULL);
}

int main()
{
    test_spinlock();
    test_mult_thread_lock();
    test_spin_wait_group();
}